import 'dart:async';
import 'package:build/build.dart';
import 'package:dart_style/dart_style.dart';
import 'package:string_scanner/string_scanner.dart';
import 'package:yacc/yacc.dart';

Builder yaccBuilder(_) => const YaccBuilder();

class YaccBuilder implements Builder {
  const YaccBuilder();

  @override
  Map<String, List<String>> get buildExtensions {
    return const {
      '.dartl': ['.lex.dart'],
      '.darty': ['.yacc.dart'],
    };
  }

  @override
  Future build(BuildStep buildStep) async {
    var contents = await buildStep.readAsString(buildStep.inputId);
    var scanner = SpanScanner(contents, sourceUrl: buildStep.inputId.uri);
    var isYacc = buildStep.inputId.extension == '.darty';
    var grammar = isYacc ? parseYaccGrammar(scanner) : parseLexGrammar(scanner);
    var gen = isYacc ? Yacc(grammar) : Lex(grammar);
    await buildStep.writeAsString(
      buildStep.inputId.changeExtension(isYacc ? '.yacc.dart' : '.lex.dart'),
      DartFormatter().format(gen.buildToString()),
    );
  }
}
